home *** CD-ROM | disk | FTP | other *** search
/ PC World 2008 February (DVD) / PCWorld_2008-02_DVD.iso / v cisle / PHP / PHP.exe / xampp-win32-1.6.5-installer.exe / php / PEAR / Auth.php < prev    next >
Encoding:
PHP Script  |  2007-12-20  |  35.3 KB  |  1,267 lines

  1. <?php
  2. /* vim: set expandtab tabstop=4 shiftwidth=4 softtabstop=4 foldmethod=marker: */
  3.  
  4. /**
  5.  * The main include file for Auth package
  6.  *
  7.  * PHP versions 4 and 5
  8.  *
  9.  * LICENSE: This source file is subject to version 3.01 of the PHP license
  10.  * that is available through the world-wide-web at the following URI:
  11.  * http://www.php.net/license/3_01.txt.  If you did not receive a copy of
  12.  * the PHP License and are unable to obtain it through the web, please
  13.  * send a note to license@php.net so we can mail you a copy immediately.
  14.  *
  15.  * @category   Authentication
  16.  * @package    Auth
  17.  * @author     Martin Jansen <mj@php.net>
  18.  * @author     Adam Ashley <aashley@php.net>
  19.  * @copyright  2001-2006 The PHP Group
  20.  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  21.  * @version    CVS: $Id: Auth.php,v 1.115 2007/02/02 00:41:14 aashley Exp $
  22.  * @link       http://pear.php.net/package/Auth
  23.  */
  24.  
  25. /**
  26.  * Returned if session exceeds idle time
  27.  */
  28. define('AUTH_IDLED',                    -1);
  29. /**
  30.  * Returned if session has expired
  31.  */
  32. define('AUTH_EXPIRED',                  -2);
  33. /** 
  34.  * Returned if container is unable to authenticate user/password pair
  35.  */
  36. define('AUTH_WRONG_LOGIN',              -3);
  37. /**
  38.  * Returned if a container method is not supported.
  39.  */
  40. define('AUTH_METHOD_NOT_SUPPORTED',     -4);
  41. /**
  42.  * Returned if new Advanced security system detects a breach
  43.  */
  44. define('AUTH_SECURITY_BREACH',          -5);
  45. /**
  46.  * Returned if checkAuthCallback says session should not continue.
  47.  */
  48. define('AUTH_CALLBACK_ABORT',           -6);
  49.  
  50. /**
  51.  * Auth Log level - INFO
  52.  */
  53. define('AUTH_LOG_INFO',     6);
  54. /**
  55.  * Auth Log level - DEBUG
  56.  */
  57. define('AUTH_LOG_DEBUG',    7);
  58.  
  59.  
  60. /**
  61.  * PEAR::Auth
  62.  *
  63.  * The PEAR::Auth class provides methods for creating an
  64.  * authentication system using PHP.
  65.  *
  66.  * @category   Authentication
  67.  * @package    Auth
  68.  * @author     Martin Jansen <mj@php.net>
  69.  * @author     Adam Ashley <aashley@php.net>
  70.  * @copyright  2001-2006 The PHP Group
  71.  * @license    http://www.php.net/license/3_01.txt  PHP License 3.01
  72.  * @version    Release: 1.5.0  File: $Revision: 1.115 $
  73.  * @link       http://pear.php.net/package/Auth
  74.  */
  75. class Auth {
  76.  
  77.     // {{{ properties
  78.  
  79.     /**
  80.      * Auth lifetime in seconds
  81.      *
  82.      * If this variable is set to 0, auth never expires
  83.      *
  84.      * @var  integer
  85.      * @see  setExpire(), checkAuth()
  86.      */
  87.     var $expire = 0;
  88.  
  89.     /**
  90.      * Has the auth session expired?
  91.      *
  92.      * @var   bool
  93.      * @see   checkAuth()
  94.      */
  95.     var $expired = false;
  96.  
  97.     /**
  98.      * Maximum idletime in seconds
  99.      *
  100.      * The difference to $expire is, that the idletime gets
  101.      * refreshed each time checkAuth() is called. If this
  102.      * variable is set to 0, idletime is never checked.
  103.      *
  104.      * @var integer
  105.      * @see setIdle(), checkAuth()
  106.      */
  107.     var $idle = 0;
  108.  
  109.     /**
  110.      * Is the maximum idletime over?
  111.      *
  112.      * @var boolean
  113.      * @see checkAuth()
  114.      */
  115.     var $idled = false;
  116.  
  117.     /**
  118.      * Storage object
  119.      *
  120.      * @var object
  121.      * @see Auth(), validateLogin()
  122.      */
  123.     var $storage = '';
  124.  
  125.     /**
  126.      * User-defined function that creates the login screen
  127.      *
  128.      * @var string
  129.      */
  130.     var $loginFunction = '';
  131.  
  132.     /**
  133.      * Should the login form be displayed
  134.      *
  135.      * @var   bool
  136.      * @see   setShowlogin()
  137.      */
  138.     var $showLogin = true;
  139.     
  140.     /**
  141.       * Is Login Allowed from this page
  142.       *
  143.       * @var  bool
  144.       * @see setAllowLogin
  145.       */
  146.     var $allowLogin = true;
  147.  
  148.     /**
  149.      * Current authentication status
  150.      *
  151.      * @var string
  152.      */
  153.     var $status = '';
  154.  
  155.     /**
  156.      * Username
  157.      *
  158.      * @var string
  159.      */
  160.     var $username = '';
  161.  
  162.     /**
  163.      * Password
  164.      *
  165.      * @var string
  166.      */
  167.     var $password = '';
  168.  
  169.     /**
  170.      * checkAuth callback function name
  171.      *
  172.      * @var string
  173.      * @see setCheckAuthCallback()
  174.      */
  175.     var $checkAuthCallback = '';
  176.  
  177.     /**
  178.      * Login callback function name
  179.      *
  180.      * @var string
  181.      * @see setLoginCallback()
  182.      */
  183.     var $loginCallback = '';
  184.  
  185.     /**
  186.      * Failed Login callback function name
  187.      *
  188.      * @var string
  189.      * @see setFailedLoginCallback()
  190.      */
  191.     var $loginFailedCallback = '';
  192.  
  193.     /**
  194.      * Logout callback function name
  195.      *
  196.      * @var string
  197.      * @see setLogoutCallback()
  198.      */
  199.     var $logoutCallback = '';
  200.  
  201.     /**
  202.      * Auth session-array name
  203.      *
  204.      * @var string
  205.      */
  206.     var $_sessionName = '_authsession';
  207.  
  208.     /**
  209.      * Package Version
  210.      *
  211.      * @var string
  212.      */
  213.     var $version = "@version@";
  214.  
  215.     /**
  216.      * Flag to use advanced security
  217.      * When set extra checks will be made to see if the 
  218.      * user's IP or useragent have changed across requests. 
  219.      * Turned off by default to preserve BC.
  220.      *
  221.      * @var boolean
  222.      */     
  223.     var $advancedsecurity = false;
  224.  
  225.     /**
  226.      * Username key in POST array
  227.      *
  228.      * @var string
  229.      */
  230.     var $_postUsername = 'username';
  231.  
  232.     /**
  233.      * Password key in POST array
  234.      *
  235.      * @var string
  236.      */
  237.     var $_postPassword = 'password';
  238.  
  239.     /**
  240.      * Holds a reference to the session auth variable
  241.      * @var array
  242.      */
  243.     var $session;
  244.  
  245.     /**
  246.      * Holds a reference to the global server variable
  247.      * @var array
  248.      */
  249.     var $server;
  250.  
  251.     /**
  252.      * Holds a reference to the global post variable
  253.      * @var array
  254.      */
  255.     var $post;
  256.  
  257.     /**
  258.      * Holds a reference to the global cookie variable
  259.      * @var array
  260.      */
  261.     var $cookie;
  262.  
  263.     /**
  264.      * A hash to hold various superglobals as reference
  265.      * @var array
  266.      */
  267.     var $authdata;
  268.     
  269.     /**
  270.       * How many times has checkAuth been called
  271.       * @var int
  272.       */
  273.     var $authChecks = 0;
  274.  
  275.     /**
  276.      * PEAR::Log object
  277.      *
  278.      * @var object Log
  279.      */
  280.     var $logger = null;
  281.  
  282.     /**
  283.      * Whether to enable logging of behaviour
  284.      *
  285.      * @var boolean
  286.      */
  287.     var $enableLogging = false;
  288.  
  289.     // }}}
  290.     // {{{ Auth() [constructor]
  291.  
  292.     /**
  293.      * Constructor
  294.      *
  295.      * Set up the storage driver.
  296.      *
  297.      * @param string    Type of the storage driver
  298.      * @param mixed     Additional options for the storage driver
  299.      *                  (example: if you are using DB as the storage
  300.      *                   driver, you have to pass the dsn string here)
  301.      *
  302.      * @param string    Name of the function that creates the login form
  303.      * @param boolean   Should the login form be displayed if neccessary?
  304.      * @return void
  305.      */
  306.     function Auth($storageDriver, $options = '', $loginFunction = '', $showLogin = true)
  307.     {
  308.         $this->applyAuthOptions($options);
  309.  
  310.         // Start the session suppress error if already started
  311.         if(!session_id()){
  312.             @session_start();
  313.             if(!session_id()) {
  314.                 // Throw error
  315.                 include_once 'PEAR.php';
  316.                 PEAR::throwError('Session could not be started by Auth, '
  317.                         .'possibly headers are already sent, try putting '
  318.                         .'ob_start in the beginning of your script');
  319.             }
  320.         }
  321.  
  322.         // Make Sure Auth session variable is there
  323.         if(!isset($_SESSION[$this->_sessionName])) {
  324.             $_SESSION[$this->_sessionName] = array();
  325.         }
  326.  
  327.         // Assign Some globals to internal references, this will replace _importGlobalVariable
  328.         $this->session =& $_SESSION[$this->_sessionName];
  329.         $this->server =& $_SERVER;
  330.         $this->post =& $_POST;
  331.         $this->cookie =& $_COOKIE;
  332.  
  333.         if ($loginFunction != '' && is_callable($loginFunction)) {
  334.             $this->loginFunction = $loginFunction;
  335.         }
  336.  
  337.         if (is_bool($showLogin)) {
  338.             $this->showLogin = $showLogin;
  339.         }
  340.  
  341.         if (is_object($storageDriver)) {
  342.             $this->storage =& $storageDriver;
  343.             // Pass a reference to auth to the container, ugly but works
  344.             // this is used by the DB container to use method setAuthData not staticaly.
  345.             $this->storage->_auth_obj =& $this;
  346.         } else {
  347.             // $this->storage = $this->_factory($storageDriver, $options);
  348.             // 
  349.             $this->storage_driver = $storageDriver;
  350.             $this->storage_options =& $options;
  351.         }
  352.     }
  353.  
  354.     // }}}
  355.     // {{{ applyAuthOptions()
  356.  
  357.     /**
  358.       * Set the Auth options 
  359.       *
  360.       * Some options which are Auth specific will be applied
  361.       * the rest will be left for usage by the container
  362.       * 
  363.       * @param array    An array of Auth options
  364.       * @return array   The options which were not applied
  365.       * @access private
  366.       */
  367.     function &applyAuthOptions(&$options)
  368.     {
  369.         if(is_array($options)){
  370.             if (!empty($options['sessionName'])) {
  371.                 $this->_sessionName = $options['sessionName'];
  372.                 unset($options['sessionName']);
  373.             }
  374.             if (isset($options['allowLogin'])) {
  375.                 $this->allowLogin = $options['allowLogin'];
  376.                 unset($options['allowLogin']);
  377.             }
  378.             if (!empty($options['postUsername'])) {
  379.                 $this->_postUsername = $options['postUsername'];
  380.                 unset($options['postUsername']);
  381.             }
  382.             if (!empty($options['postPassword'])) {
  383.                 $this->_postPassword = $options['postPassword'];
  384.                 unset($options['postPassword']);
  385.             }
  386.             if (isset($options['advancedsecurity'])) {
  387.                 $this->advancedsecurity = $options['advancedsecurity'];
  388.                 unset($options['advancedsecurity']);
  389.             }
  390.             if (isset($options['enableLogging'])) {
  391.                 $this->enableLogging = $options['enableLogging'];
  392.                 unset($options['enableLogging']);
  393.             }
  394.         }
  395.         return($options);
  396.     }
  397.  
  398.     // }}}
  399.     // {{{ _loadStorage()
  400.     
  401.     /**
  402.       * Load Storage Driver if not already loaded
  403.       *
  404.       * Suspend storage instantiation to make Auth lighter to use 
  405.       * for calls which do not require login
  406.       *
  407.       * @return bool    True if the conainer is loaded, false if the container
  408.       *                 is already loaded
  409.       * @access private
  410.       */
  411.     function _loadStorage()
  412.     {
  413.         if(!is_object($this->storage)) {
  414.             $this->storage =& $this->_factory($this->storage_driver, 
  415.                     $this->storage_options);
  416.             $this->storage->_auth_obj =& $this;
  417.             $this->log('Loaded storage container ('.$this->storage_driver.')', AUTH_LOG_DEBUG);
  418.             return(true);
  419.         }
  420.         return(false);
  421.     }
  422.  
  423.     // }}}
  424.     // {{{ _factory()
  425.  
  426.     /**
  427.      * Return a storage driver based on $driver and $options
  428.      *
  429.      * @static
  430.      * @param  string $driver  Type of storage class to return
  431.      * @param  string $options Optional parameters for the storage class
  432.      * @return object Object   Storage object
  433.      * @access private
  434.      */
  435.     function &_factory($driver, $options = '')
  436.     {
  437.         $storage_class = 'Auth_Container_' . $driver;
  438.         include_once 'Auth/Container/' . $driver . '.php';
  439.         $obj =& new $storage_class($options);
  440.         return $obj;
  441.     }
  442.  
  443.     // }}}
  444.     // {{{ assignData()
  445.  
  446.     /**
  447.      * Assign data from login form to internal values
  448.      *
  449.      * This function takes the values for username and password
  450.      * from $HTTP_POST_VARS/$_POST and assigns them to internal variables.
  451.      * If you wish to use another source apart from $HTTP_POST_VARS/$_POST,
  452.      * you have to derive this function.
  453.      *
  454.      * @global $HTTP_POST_VARS, $_POST
  455.      * @see    Auth
  456.      * @return void
  457.      * @access private
  458.      */
  459.     function assignData()
  460.     {
  461.         $this->log('Auth::assignData() called.', AUTH_LOG_DEBUG);
  462.  
  463.         if (   isset($this->post[$this->_postUsername]) 
  464.             && $this->post[$this->_postUsername] != '') {
  465.             $this->username = (get_magic_quotes_gpc() == 1 
  466.                     ? stripslashes($this->post[$this->_postUsername]) 
  467.                     : $this->post[$this->_postUsername]);
  468.         }
  469.         if (   isset($this->post[$this->_postPassword]) 
  470.             && $this->post[$this->_postPassword] != '') {
  471.             $this->password = (get_magic_quotes_gpc() == 1 
  472.                     ? stripslashes($this->post[$this->_postPassword]) 
  473.                     : $this->post[$this->_postPassword] );
  474.         }
  475.     }
  476.  
  477.     // }}}
  478.     // {{{ start()
  479.  
  480.     /**
  481.      * Start new auth session
  482.      *
  483.      * @return void
  484.      * @access public
  485.      */
  486.     function start()
  487.     {
  488.         $this->log('Auth::start() called.', AUTH_LOG_DEBUG);
  489.  
  490.         $this->assignData();
  491.         if (!$this->checkAuth() && $this->allowLogin) {
  492.             $this->login();
  493.         }
  494.     }
  495.  
  496.     // }}}
  497.     // {{{ login()
  498.  
  499.     /**
  500.      * Login function
  501.      *
  502.      * @return void
  503.      * @access private
  504.      */
  505.     function login()
  506.     {
  507.         $this->log('Auth::login() called.', AUTH_LOG_DEBUG);
  508.  
  509.         $login_ok = false;
  510.         $this->_loadStorage();
  511.         
  512.         // Check if using challenge response
  513.         (isset($this->post['authsecret']) && $this->post['authsecret'] == 1) 
  514.             ? $usingChap = true 
  515.             : $usingChap = false;
  516.  
  517.         
  518.         // When the user has already entered a username, we have to validate it.
  519.         if (!empty($this->username)) {
  520.             if (true === $this->storage->fetchData($this->username, $this->password, $usingChap)) {
  521.                 $this->session['challengekey'] = md5($this->username.$this->password);
  522.                 $login_ok = true;
  523.                 $this->log('Successful login.', AUTH_LOG_INFO);
  524.             }
  525.         }
  526.  
  527.         if (!empty($this->username) && $login_ok) {
  528.             $this->setAuth($this->username);
  529.             if (is_callable($this->loginCallback)) {
  530.                 $this->log('Calling loginCallback ('.$this->loginCallback.').', AUTH_LOG_DEBUG);
  531.                 call_user_func_array($this->loginCallback, array($this->username, &$this));
  532.             }
  533.         }
  534.  
  535.         // If the login failed or the user entered no username, 
  536.         // output the login screen again.
  537.         if (!empty($this->username) && !$login_ok) {
  538.             $this->log('Incorrect login.', AUTH_LOG_INFO);
  539.             $this->status = AUTH_WRONG_LOGIN;
  540.             if (is_callable($this->loginFailedCallback)) {
  541.                 $this->log('Calling loginFailedCallback ('.$this->loginFailedCallback.').', AUTH_LOG_DEBUG);
  542.                 call_user_func_array($this->loginFailedCallback, array($this->username, &$this));
  543.             }
  544.         }
  545.  
  546.         if ((empty($this->username) || !$login_ok) && $this->showLogin) {
  547.             $this->log('Rendering Login Form.', AUTH_LOG_INFO);
  548.             if (is_callable($this->loginFunction)) {
  549.                 $this->log('Calling loginFunction ('.$this->loginFunction.').', AUTH_LOG_DEBUG);
  550.                 call_user_func_array($this->loginFunction, array($this->username, $this->status, &$this));
  551.             } else {
  552.                 // BC fix Auth used to use drawLogin for this
  553.                 // call is sub classes implement this
  554.                 if (is_callable(array($this, 'drawLogin'))) {
  555.                     $this->log('Calling Auth::drawLogin()', AUTH_LOG_DEBUG);
  556.                     return $this->drawLogin($this->username, $this);
  557.                 }
  558.  
  559.                 $this->log('Using default Auth_Frontend_Html', AUTH_LOG_DEBUG);
  560.  
  561.                 // New Login form
  562.                 include_once 'Auth/Frontend/Html.php';
  563.                 return Auth_Frontend_Html::render($this, $this->username);
  564.             }
  565.         } else {
  566.             return;
  567.         }
  568.     }
  569.  
  570.     // }}}
  571.     // {{{ setExpire()
  572.  
  573.     /**
  574.      * Set the maximum expire time
  575.      *
  576.      * @param  integer time in seconds
  577.      * @param  bool    add time to current expire time or not
  578.      * @return void
  579.      * @access public
  580.      */
  581.     function setExpire($time, $add = false)
  582.     {
  583.         $add ? $this->expire += $time : $this->expire = $time;
  584.     }
  585.  
  586.     // }}}
  587.     // {{{ setIdle()
  588.  
  589.     /**
  590.      * Set the maximum idle time
  591.      *
  592.      * @param  integer time in seconds
  593.      * @param  bool    add time to current maximum idle time or not
  594.      * @return void
  595.      * @access public
  596.      */
  597.     function setIdle($time, $add = false)
  598.     {
  599.         $add ? $this->idle += $time : $this->idle = $time;
  600.     }
  601.  
  602.     // }}}
  603.     // {{{ setSessionName()
  604.  
  605.     /**
  606.      * Set name of the session to a customized value.
  607.      *
  608.      * If you are using multiple instances of PEAR::Auth
  609.      * on the same domain, you can change the name of
  610.      * session per application via this function.
  611.      * This will chnage the name of the session variable 
  612.      * auth uses to store it's data in the session
  613.      *
  614.      * @param  string New name for the session
  615.      * @return void
  616.      * @access public
  617.      */
  618.     function setSessionName($name = 'session')
  619.     {
  620.         $this->_sessionName = '_auth_'.$name;
  621.         $this->session =& $_SESSION[$this->_sessionName];
  622.     }
  623.  
  624.     // }}}
  625.     // {{{ setShowLogin()
  626.  
  627.     /**
  628.      * Should the login form be displayed if neccessary?
  629.      *
  630.      * @param  bool    show login form or not
  631.      * @return void
  632.      * @access public
  633.      */
  634.     function setShowLogin($showLogin = true)
  635.     {
  636.         $this->showLogin = $showLogin;
  637.     }
  638.  
  639.     // }}}
  640.     // {{{ setAllowLogin()
  641.  
  642.     /**
  643.      * Should the login form be displayed if neccessary?
  644.      *
  645.      * @param  bool    show login form or not
  646.      * @return void
  647.      * @access public
  648.      */
  649.     function setAllowLogin($allowLogin = true)
  650.     {
  651.         $this->allowLogin = $allowLogin;
  652.     }
  653.  
  654.     // }}}
  655.     // {{{ setCheckAuthCallback()
  656.  
  657.     /**
  658.      * Register a callback function to be called whenever the validity of the login is checked
  659.      * The function will receive two parameters, the username and a reference to the auth object.
  660.      *
  661.      * @param  string  callback function name
  662.      * @return void
  663.      * @access public
  664.      * @since Method available since Release 1.4.3
  665.      */
  666.     function setCheckAuthCallback($checkAuthCallback)
  667.     {
  668.         $this->checkAuthCallback = $checkAuthCallback;
  669.     }
  670.  
  671.     // }}}
  672.     // {{{ setLoginCallback()
  673.     
  674.     /**
  675.      * Register a callback function to be called on user login.
  676.      * The function will receive two parameters, the username and a reference to the auth object.
  677.      *
  678.      * @param  string  callback function name
  679.      * @return void
  680.      * @see    setLogoutCallback()
  681.      * @access public
  682.      */
  683.     function setLoginCallback($loginCallback)
  684.     {
  685.         $this->loginCallback = $loginCallback;
  686.     }
  687.  
  688.     // }}}
  689.     // {{{ setFailedLoginCallback()
  690.  
  691.     /**
  692.      * Register a callback function to be called on failed user login.
  693.      * The function will receive two parameters, the username and a reference to the auth object.
  694.      *
  695.      * @param  string  callback function name
  696.      * @return void
  697.      * @access public
  698.      */
  699.     function setFailedLoginCallback($loginFailedCallback)
  700.     {
  701.         $this->loginFailedCallback = $loginFailedCallback;
  702.     }
  703.  
  704.     // }}}
  705.     // {{{ setLogoutCallback()
  706.  
  707.     /**
  708.      * Register a callback function to be called on user logout.
  709.      * The function will receive three parameters, the username and a reference to the auth object.
  710.      *
  711.      * @param  string  callback function name
  712.      * @return void
  713.      * @see    setLoginCallback()
  714.      * @access public
  715.      */
  716.     function setLogoutCallback($logoutCallback)
  717.     {
  718.         $this->logoutCallback = $logoutCallback;
  719.     }
  720.  
  721.     // }}}
  722.     // {{{ setAuthData()
  723.  
  724.     /**
  725.      * Register additional information that is to be stored
  726.      * in the session.
  727.      *
  728.      * @param  string  Name of the data field
  729.      * @param  mixed   Value of the data field
  730.      * @param  boolean Should existing data be overwritten? (default
  731.      *                 is true)
  732.      * @return void
  733.      * @access public
  734.      */
  735.     function setAuthData($name, $value, $overwrite = true)
  736.     {
  737.         if (!empty($this->session['data'][$name]) && $overwrite == false) {
  738.             return;
  739.         }
  740.         $this->session['data'][$name] = $value;
  741.     }
  742.  
  743.     // }}}
  744.     // {{{ getAuthData()
  745.  
  746.     /**
  747.      * Get additional information that is stored in the session.
  748.      *
  749.      * If no value for the first parameter is passed, the method will
  750.      * return all data that is currently stored.
  751.      *
  752.      * @param  string Name of the data field
  753.      * @return mixed  Value of the data field.
  754.      * @access public
  755.      */
  756.     function getAuthData($name = null)
  757.     {
  758.         if (!isset($this->session['data'])) {
  759.             return null;
  760.         }    
  761.         if(!isset($name)) {
  762.             return $this->session['data'];
  763.         }
  764.         if (isset($name) && isset($this->session['data'][$name])) {
  765.             return $this->session['data'][$name];
  766.         }
  767.         return null;        
  768.     }
  769.  
  770.     // }}}
  771.     // {{{ setAuth()
  772.  
  773.     /**
  774.      * Register variable in a session telling that the user
  775.      * has logged in successfully
  776.      *
  777.      * @param  string Username
  778.      * @return void
  779.      * @access public
  780.      */
  781.     function setAuth($username)
  782.     {
  783.         $this->log('Auth::setAuth() called.', AUTH_LOG_DEBUG);
  784.     
  785.         // #2021 - Change the session id to avoid session fixation attacks php 4.3.3 > 
  786.         session_regenerate_id(true);
  787.  
  788.         if (!isset($this->session) || !is_array($this->session)) {
  789.             $this->session = array();
  790.         }
  791.  
  792.         if (!isset($this->session['data'])) {
  793.             $this->session['data'] = array();
  794.         }
  795.  
  796.         $this->session['sessionip'] = isset($this->server['REMOTE_ADDR']) 
  797.             ? $this->server['REMOTE_ADDR'] 
  798.             : '';
  799.         $this->session['sessionuseragent'] = isset($this->server['HTTP_USER_AGENT']) 
  800.             ? $this->server['HTTP_USER_AGENT'] 
  801.             : '';
  802.         $this->session['sessionforwardedfor'] = isset($this->server['HTTP_X_FORWARDED_FOR']) 
  803.             ? $this->server['HTTP_X_FORWARDED_FOR'] 
  804.             : '';
  805.  
  806.         // This should be set by the container to something more safe
  807.         // Like md5(passwd.microtime)
  808.         if(empty($this->session['challengekey'])) {
  809.             $this->session['challengekey'] = md5($username.microtime());
  810.         }
  811.  
  812.         $this->session['challengecookie'] = md5($this->session['challengekey'].microtime());
  813.         setcookie('authchallenge', $this->session['challengecookie']);
  814.  
  815.         $this->session['registered'] = true;
  816.         $this->session['username']   = $username;
  817.         $this->session['timestamp']  = time();
  818.         $this->session['idle']       = time();
  819.     }
  820.  
  821.     // }}}
  822.     // {{{ setAdvancedSecurity()
  823.     
  824.     /**
  825.       * Enables advanced security checks
  826.       *
  827.       * Currently only ip change and useragent change 
  828.       * are detected
  829.       * @todo Add challenge cookies - Create a cookie which changes every time 
  830.       *       and contains some challenge key which the server can verify with
  831.       *       a session var cookie might need to be crypted (user pass)
  832.       * @param bool Enable or disable
  833.       * @return void
  834.       * @access public
  835.       */
  836.     function setAdvancedSecurity($flag=true)
  837.     {
  838.         $this->advancedsecurity = $flag;
  839.     }
  840.  
  841.     // }}}
  842.     // {{{ checkAuth()
  843.  
  844.     /**
  845.      * Checks if there is a session with valid auth information.
  846.      *
  847.      * @access public
  848.      * @return boolean  Whether or not the user is authenticated.
  849.      */
  850.     function checkAuth()
  851.     {
  852.         $this->log('Auth::checkAuth() called.', AUTH_LOG_DEBUG);
  853.         $this->authChecks++;
  854.         if (isset($this->session)) {
  855.             // Check if authentication session is expired
  856.             if (   $this->expire > 0
  857.                 && isset($this->session['timestamp'])
  858.                 && ($this->session['timestamp'] + $this->expire) < time()) {
  859.                 $this->log('Session Expired', AUTH_LOG_INFO);
  860.                 $this->expired = true;
  861.                 $this->status = AUTH_EXPIRED;
  862.                 $this->logout();
  863.                 return false;
  864.             }
  865.  
  866.             // Check if maximum idle time is reached
  867.             if (   $this->idle > 0
  868.                 && isset($this->session['idle']) 
  869.                 && ($this->session['idle'] + $this->idle) < time()) {
  870.                 $this->log('Session Idle Time Reached', AUTH_LOG_INFO);
  871.                 $this->idled = true;
  872.                 $this->status = AUTH_IDLED;
  873.                 $this->logout();
  874.                 return false;
  875.             }
  876.  
  877.             if (   isset($this->session['registered']) 
  878.                 && isset($this->session['username']) 
  879.                 && $this->session['registered'] == true 
  880.                 && $this->session['username'] != '') {
  881.                 Auth::updateIdle();
  882.  
  883.                 if ($this->advancedsecurity) {
  884.                     $this->log('Advanced Security Mode Enabled.', AUTH_LOG_DEBUG);
  885.                     
  886.                     // Only Generate the challenge once
  887.                     if($this->authChecks == 1) {
  888.                         $this->log('Generating new Challenge Cookie.', AUTH_LOG_DEBUG);
  889.                         $this->session['challengecookieold'] = $this->session['challengecookie'];
  890.                         $this->session['challengecookie'] = md5($this->session['challengekey'].microtime());
  891.                         setcookie('authchallenge', $this->session['challengecookie']);
  892.                     }
  893.                     
  894.                     // Check for ip change
  895.                     if (   isset($this->server['REMOTE_ADDR']) 
  896.                         && $this->session['sessionip'] != $this->server['REMOTE_ADDR']) {
  897.                         $this->log('Security Breach. Remote IP Address changed.', AUTH_LOG_INFO);
  898.                         // Check if the IP of the user has changed, if so we 
  899.                         // assume a man in the middle attack and log him out
  900.                         $this->expired = true;
  901.                         $this->status = AUTH_SECURITY_BREACH;
  902.                         $this->logout();
  903.                         return false;
  904.                     }
  905.  
  906.                     // Check for ip change (if connected via proxy)
  907.                     if (   isset($this->server['HTTP_X_FORWARDED_FOR'])
  908.                         && $this->session['sessionforwardedfor'] != $this->server['HTTP_X_FORWARDED_FOR']) {
  909.                         $this->log('Security Breach. Forwarded For IP Address changed.', AUTH_LOG_INFO);
  910.                         // Check if the IP of the user connecting via proxy has 
  911.                         // changed, if so we assume a man in the middle attack 
  912.                         // and log him out.
  913.                         $this->expired = true;
  914.                         $this->status = AUTH_SECURITY_BREACH;
  915.                         $this->logout();
  916.                         return false;
  917.                     }
  918.                     
  919.                     // Check for useragent change
  920.                     if (   isset($this->server['HTTP_USER_AGENT']) 
  921.                         && $this->session['sessionuseragent'] != $this->server['HTTP_USER_AGENT']) {
  922.                         $this->log('Security Breach. User Agent changed.', AUTH_LOG_INFO);
  923.                         // Check if the User-Agent of the user has changed, if 
  924.                         // so we assume a man in the middle attack and log him out
  925.                         $this->expired = true;
  926.                         $this->status = AUTH_SECURITY_BREACH;
  927.                         $this->logout();
  928.                         return false;
  929.                     }
  930.     
  931.                     // Check challenge cookie here, if challengecookieold is not set 
  932.                     // this is the first time and check is skipped
  933.                     // TODO when user open two pages similtaneuly (open in new window,open 
  934.                     // in tab) auth breach is caused find out a way around that if possible
  935.                     if (   isset($this->session['challengecookieold']) 
  936.                         && $this->session['challengecookieold'] != $this->cookie['authchallenge']) {
  937.                         $this->log('Security Breach. Challenge Cookie mismatch.', AUTH_LOG_INFO);
  938.                         $this->expired = true;
  939.                         $this->status = AUTH_SECURITY_BREACH;
  940.                         $this->logout();
  941.                         $this->login();
  942.                         return false;
  943.                     }
  944.                 }
  945.  
  946.                 if (is_callable($this->checkAuthCallback)) {
  947.                     $this->log('Calling checkAuthCallback ('.$this->checkAuthCallback.').', AUTH_LOG_DEBUG);
  948.                     $checkCallback = call_user_func_array($this->checkAuthCallback, array($this->username, &$this));
  949.                     if ($checkCallback == false) {
  950.                         $this->log('checkAuthCallback failed.', AUTH_LOG_INFO);
  951.                         $this->expired = true;
  952.                         $this->status = AUTH_CALLBACK_ABORT;
  953.                         $this->logout();
  954.                         return false;
  955.                     }
  956.                 }
  957.  
  958.                 $this->log('Session OK.', AUTH_LOG_INFO);
  959.                 return true;
  960.             }
  961.         }
  962.         $this->log('Unable to locate session storage.', AUTH_LOG_DEBUG);
  963.         return false;
  964.     }
  965.  
  966.     // }}}
  967.     // {{{ staticCheckAuth() [static]
  968.  
  969.     /**
  970.      * Statically checks if there is a session with valid auth information.
  971.      *
  972.      * @access public
  973.      * @see checkAuth
  974.      * @return boolean  Whether or not the user is authenticated.
  975.      * @static
  976.      */
  977.     function staticCheckAuth($options = null)
  978.     {
  979.         static $staticAuth;
  980.         if(!isset($staticAuth)) {
  981.             $staticAuth = new Auth('null', $options);
  982.         }
  983.         $staticAuth->log('Auth::staticCheckAuth() called', AUTH_LOG_DEBUG);
  984.         return $staticAuth->checkAuth();
  985.     }
  986.  
  987.     // }}}
  988.     // {{{ getAuth()
  989.  
  990.     /**
  991.      * Has the user been authenticated?
  992.      *
  993.      * @access public
  994.      * @return bool  True if the user is logged in, otherwise false.
  995.      */
  996.     function getAuth()
  997.     {
  998.         $this->log('Auth::getAuth() called.', AUTH_LOG_DEBUG);
  999.         return $this->checkAuth();
  1000.     }
  1001.  
  1002.     // }}}
  1003.     // {{{ logout()
  1004.  
  1005.     /**
  1006.      * Logout function
  1007.      *
  1008.      * This function clears any auth tokens in the currently
  1009.      * active session and executes the logout callback function,
  1010.      * if any
  1011.      *
  1012.      * @access public
  1013.      * @return void
  1014.      */
  1015.     function logout()
  1016.     {
  1017.         $this->log('Auth::logout() called.', AUTH_LOG_DEBUG);
  1018.  
  1019.         if (is_callable($this->logoutCallback)) {
  1020.             $this->log('Calling logoutCallback ('.$this->logoutCallback.').', AUTH_LOG_DEBUG);
  1021.             call_user_func_array($this->logoutCallback, array($this->session['username'], &$this));
  1022.         }
  1023.  
  1024.         $this->username = '';
  1025.         $this->password = '';
  1026.         
  1027.         $this->session = null;
  1028.     }
  1029.  
  1030.     // }}}
  1031.     // {{{ updateIdle()
  1032.  
  1033.     /**
  1034.      * Update the idletime
  1035.      *
  1036.      * @access private
  1037.      * @return void
  1038.      */
  1039.     function updateIdle()
  1040.     {
  1041.         $this->session['idle'] = time();
  1042.     }
  1043.  
  1044.     // }}}
  1045.     // {{{ getUsername()
  1046.  
  1047.     /**
  1048.      * Get the username
  1049.      *
  1050.      * @return string
  1051.      * @access public
  1052.      */
  1053.     function getUsername()
  1054.     {
  1055.         if (isset($this->session['username'])) {
  1056.             return($this->session['username']);
  1057.         }
  1058.         return('');
  1059.     }
  1060.  
  1061.     // }}}
  1062.     // {{{ getStatus()
  1063.  
  1064.     /**
  1065.      * Get the current status
  1066.      *
  1067.      * @return string
  1068.      * @access public
  1069.      */
  1070.     function getStatus()
  1071.     {
  1072.         return $this->status;
  1073.     }
  1074.  
  1075.     // }}}
  1076.     // {{{ getPostUsernameField()
  1077.     
  1078.     /**
  1079.      * Gets the post varible used for the username
  1080.      * 
  1081.      * @return string
  1082.      * @access public
  1083.      */
  1084.     function getPostUsernameField()
  1085.     {
  1086.         return($this->_postUsername);
  1087.     }
  1088.  
  1089.     // }}}
  1090.     // {{{ getPostPasswordField()
  1091.  
  1092.     /**
  1093.      * Gets the post varible used for the username
  1094.      * 
  1095.      * @return string
  1096.      * @access public
  1097.      */
  1098.     function getPostPasswordField()
  1099.     {
  1100.         return($this->_postPassword);
  1101.     }
  1102.  
  1103.     // }}}
  1104.     // {{{ sessionValidThru()
  1105.  
  1106.     /**
  1107.      * Returns the time up to the session is valid
  1108.      *
  1109.      * @access public
  1110.      * @return integer
  1111.      */
  1112.     function sessionValidThru()
  1113.     {
  1114.         if (!isset($this->session['idle'])) {
  1115.             return 0;
  1116.         }
  1117.         if ($this->idle == 0) {
  1118.             return 0;
  1119.         }
  1120.         return ($this->session['idle'] + $this->idle);
  1121.     }
  1122.  
  1123.     // }}}
  1124.     // {{{ listUsers()
  1125.  
  1126.     /**
  1127.      * List all users that are currently available in the storage
  1128.      * container
  1129.      *
  1130.      * @access public
  1131.      * @return array
  1132.      */
  1133.     function listUsers()
  1134.     {
  1135.         $this->log('Auth::listUsers() called.', AUTH_LOG_DEBUG);
  1136.         $this->_loadStorage();
  1137.         return $this->storage->listUsers();
  1138.     }
  1139.  
  1140.     // }}}
  1141.     // {{{ addUser()
  1142.  
  1143.     /**
  1144.      * Add user to the storage container
  1145.      *
  1146.      * @access public
  1147.      * @param  string Username
  1148.      * @param  string Password
  1149.      * @param  mixed  Additional parameters
  1150.      * @return mixed  True on success, PEAR error object on error
  1151.      *                and AUTH_METHOD_NOT_SUPPORTED otherwise.
  1152.      */
  1153.     function addUser($username, $password, $additional = '')
  1154.     {
  1155.         $this->log('Auth::addUser() called.', AUTH_LOG_DEBUG);
  1156.         $this->_loadStorage();
  1157.         return $this->storage->addUser($username, $password, $additional);
  1158.     }
  1159.  
  1160.     // }}}
  1161.     // {{{ removeUser()
  1162.  
  1163.     /**
  1164.      * Remove user from the storage container
  1165.      *
  1166.      * @access public
  1167.      * @param  string Username
  1168.      * @return mixed  True on success, PEAR error object on error
  1169.      *                and AUTH_METHOD_NOT_SUPPORTED otherwise.
  1170.      */
  1171.     function removeUser($username)
  1172.     {
  1173.         $this->log('Auth::removeUser() called.', AUTH_LOG_DEBUG);
  1174.         $this->_loadStorage();
  1175.         return $this->storage->removeUser($username);
  1176.     }
  1177.  
  1178.     // }}}
  1179.     // {{{ changePassword()
  1180.  
  1181.     /**
  1182.      * Change password for user in the storage container
  1183.      *
  1184.      * @access public
  1185.      * @param string Username
  1186.      * @param string The new password 
  1187.      * @return mixed True on success, PEAR error object on error
  1188.      *               and AUTH_METHOD_NOT_SUPPORTED otherwise.
  1189.      */
  1190.     function changePassword($username, $password)
  1191.     {
  1192.         $this->log('Auth::changePassword() called', AUTH_LOG_DEBUG);
  1193.         $this->_loadStorage();
  1194.         return $this->storage->changePassword($username, $password);
  1195.     }
  1196.  
  1197.     // }}}
  1198.     // {{{ log()
  1199.  
  1200.     /**
  1201.      * Log a message from the Auth system
  1202.      *
  1203.      * @access public
  1204.      * @param string The message to log
  1205.      * @param string The log level to log the message under. See the Log documentation for more info.
  1206.      * @return boolean
  1207.      */
  1208.     function log($message, $level = AUTH_LOG_DEBUG)
  1209.     {
  1210.         if (!$this->enableLogging) return false;
  1211.  
  1212.         $this->_loadLogger();
  1213.  
  1214.         $this->logger->log('AUTH: '.$message, $level);
  1215.     }
  1216.  
  1217.     // }}}
  1218.     // {{{ _loadLogger()
  1219.  
  1220.     /**
  1221.       * Load Log object if not already loaded
  1222.       *
  1223.       * Suspend logger instantiation to make Auth lighter to use 
  1224.       * for calls which do not require logging
  1225.       *
  1226.       * @return bool    True if the logger is loaded, false if the logger
  1227.       *                 is already loaded
  1228.       * @access private
  1229.       */
  1230.     function _loadLogger()
  1231.     {
  1232.         if(is_null($this->logger)) {
  1233.             if (!class_exists('Log')) {
  1234.                 include_once 'Log.php';
  1235.             }
  1236.             $this->logger =& Log::singleton('null',
  1237.                     null,
  1238.                     'auth['.getmypid().']',
  1239.                     array(),
  1240.                     AUTH_LOG_DEBUG);
  1241.             return(true);
  1242.         }
  1243.         return(false);
  1244.     }
  1245.  
  1246.     // }}}
  1247.     // {{{ attachLogObserver()
  1248.  
  1249.     /**
  1250.      * Attach an Observer to the Auth Log Source
  1251.      *
  1252.      * @param object Log_Observer A Log Observer instance
  1253.      * @return boolean
  1254.      */
  1255.     function attachLogObserver(&$observer) {
  1256.  
  1257.         $this->_loadLogger();
  1258.  
  1259.         return $this->logger->attach($observer);
  1260.  
  1261.     }
  1262.  
  1263.     // }}}
  1264.  
  1265. }
  1266. ?>
  1267.